package cn.cq.admin.service.impl;

import cn.cq.common.BaseConst;
import cn.cq.common.NetUtils;
import cn.cq.admin.entity.dto.PasswordResetDto;
import cn.cq.admin.entity.dto.UserLoginDto;
import cn.cq.admin.entity.dto.UserModifyDto;
import cn.cq.admin.entity.dto.UserPageDto;
import cn.cq.admin.entity.model.TLoginLog;
import cn.cq.admin.entity.model.TResource;
import cn.cq.admin.entity.model.TRole;
import cn.cq.admin.entity.model.TUser;
import cn.cq.admin.entity.vo.UserVo;
import cn.cq.admin.mapper.TUserMapper;
import cn.cq.satoken.SaSecure;
import cn.cq.admin.service.TLoginLogService;
import cn.cq.admin.service.TResourceService;
import cn.cq.admin.service.TRoleService;
import cn.cq.admin.service.TUserService;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author  dicraft
 * @description 针对表【t_user(用户表)】的数据库操作Service实现
 */
@Service
@Slf4j
public class TUserServiceImpl extends ServiceImpl<TUserMapper, TUser>
        implements TUserService {

    @Resource
    private SaSecure saSecure;
    @Resource
    private TResourceService resourceService;
    @Resource
    private TLoginLogService loginLogService;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private TRoleService roleService;

    @Override
    public SaResult accountLogin(UserLoginDto loginDto, HttpServletRequest request) {
        log.info(saSecure.aesEncrypt(loginDto.getPassword()));
        String verifyCode = redisTemplate.opsForValue().get(loginDto.getVerifyKey());
        if (!loginDto.getVerifyCode().equalsIgnoreCase(verifyCode)) {
            return SaResult.error("验证码错误！");
        }
        //账号密码校验
        QueryWrapper<TUser> userQw = new QueryWrapper<>();
        userQw.eq("job_no", loginDto.getAccount());
        TUser dbUser = getOne(userQw);
        if (ObjectUtils.isEmpty(dbUser)
                || !dbUser.getPassword().equals(saSecure.aesEncrypt(loginDto.getPassword()))) {
            return SaResult.error("账号或密码错误！");
        }
        if (BaseConst.STATUS_ENABLE != dbUser.getStatus()) {
            return SaResult.error("该用户已禁用！");
        }
        StpUtil.login(dbUser.getId());
        //更新登录时间和登录IP，写入登录日志
        TLoginLog loginLog = new TLoginLog();
        loginLog.setAccount(dbUser.getJobNo());
        loginLog.setLatestTime(new Date());
        loginLog.setLatestIp(NetUtils.getIpAddress(request));
        loginLog.setUserId(dbUser.getId());
        loginLog.setUserToken(StpUtil.getTokenInfo().getTokenValue());
        loginLogService.save(loginLog);
        //设置用户登录信息
        JSONObject userJson = JSONUtil.createObj()
                .set("userName", dbUser.getActualName())
                .set("roleLabel", dbUser.getRoleLabel())
                .set("tokenName", StpUtil.getTokenInfo().getTokenName())
                .set("tokenValue", StpUtil.getTokenInfo().getTokenValue());
        //获取用户资源
        List<String> resources = getUserSource(dbUser.getRoleId());
        userJson.set("resources", resources);
        //返回结果
        return SaResult.data(userJson);
    }

    @Override
    public SaResult doCheckLogin() {
        Long userId = StpUtil.getLoginIdAsLong();
        if (ObjectUtils.isEmpty(userId)) {
            return SaResult.error("登录已过期，请重新登录！");
        }
        TUser dbUser = getById(userId);
        if (ObjectUtils.isEmpty(dbUser)) {
            return SaResult.error("登录账号异常！");
        }
        //实时获取用户的资源
        List<String> resources = getUserSource(dbUser.getRoleId());
        return SaResult.data(resources);
    }

    @Override
    public SaResult doSave(TUser user) {
        QueryWrapper<TUser> userQw = new QueryWrapper<>();
        userQw.eq("job_no", user.getJobNo())
                .or()
                .eq("mobile", user.getMobile())
                .or()
                .eq("email", user.getEmail());
        List<TUser> dbUserList = list(userQw);
        if (dbUserList.isEmpty()) {
            TUser dbUser = new TUser();
            BeanUtils.copyProperties(user, dbUser);
            user.setPassword(saSecure.aesEncrypt(user.getPassword()));
            save(user);
            return SaResult.ok("用户保存成功！");
        }
        for (TUser dbUser : dbUserList) {
            SaResult result = validateUser(user, dbUser);
            if (result.getCode() != 200) {
                return result;
            }
        }
        return SaResult.error("用户保存失败！");
    }

    @Override
    public SaResult doModify(UserModifyDto user) {
        TUser dbUser = getById(user.getId());
        if (ObjectUtils.isEmpty(dbUser)) {
            return SaResult.error("用户不存在！");
        }
        BeanUtils.copyProperties(user, dbUser);
        updateById(dbUser);
        return SaResult.ok("用户修改成功！");
    }

    @Override
    public SaResult doRemove(List<Long> ids) {
        //判断是否为当前用户
        for (Long id : ids) {
            if (id.equals(Long.parseLong((String) StpUtil.getLoginId()))) {
                return SaResult.error("不能删除当前登录用户！");
            }
        }
        if (removeByIds(ids)) {
            return SaResult.ok("用户删除成功！");
        }
        return SaResult.error("用户删除失败！");
    }

    @Override
    public SaResult doList(UserPageDto pageDto) {
        IPage<TUser> userPage = new Page<>(pageDto.getPageNo(), pageDto.getPageSize());
        IPage<UserVo> userVoPage = new Page<>();
        QueryWrapper<TUser> userQw = new QueryWrapper<>();
        if (!ObjectUtils.isEmpty(pageDto.getJobNo())) {
            userQw.eq("job_no", pageDto.getJobNo());
        }
        if (!ObjectUtils.isEmpty(pageDto.getActualName())) {
            userQw.like("actual_name", pageDto.getActualName());
        }
        if (!ObjectUtils.isEmpty(pageDto.getMobile())) {
            userQw.like("mobile", pageDto.getMobile());
        }
        if (!ObjectUtils.isEmpty(pageDto.getStatus())) {
            userQw.eq("status", pageDto.getStatus());
        }
        if (!ObjectUtils.isEmpty(pageDto.getRoleId())) {
            userQw.eq("role_id", pageDto.getRoleId());
        }
        List<TUser> userList = page(userPage, userQw).getRecords();
        List<UserVo> userVoList = userList.stream().map(user -> convertToUserVo(user))
                .collect(java.util.stream.Collectors.toList());
        userVoPage.setRecords(userVoList);
        userVoPage.setTotal(userPage.getTotal());
        userVoPage.setPages(userPage.getPages());
        userVoPage.setCurrent(userPage.getCurrent());
        return SaResult.data(userVoPage);
    }

    @Override
    public SaResult doGet() {
        Long userId = StpUtil.getLoginIdAsLong();
        if (ObjectUtils.isEmpty(userId)) {
            return SaResult.error("登录已过期，请重新登录！");
        }
        TUser dbUser = getById(userId);
        UserVo userVo = convertToUserVo(dbUser);
        return SaResult.data(userVo);
    }

    @Override
    public SaResult doPasswordReset(PasswordResetDto passwordResetDto) {
        Long userId = StpUtil.getLoginIdAsLong();
        if (ObjectUtils.isEmpty(userId)) {
            return SaResult.error("登录已过期，请重新登录！");
        }
        TUser dbUser = getById(userId);
        if (ObjectUtils.isEmpty(dbUser)) {
            return SaResult.error("登录账号异常！");
        }
        if (!saSecure.aesDecrypt(dbUser.getPassword()).equals(passwordResetDto.getPassword())) {
            return SaResult.error("旧密码错误！");
        }
        if (!passwordResetDto.getNewPassword().equals(passwordResetDto.getCheckPassword())) {
            return SaResult.error("两次新密码不一致！");
        }
        dbUser.setPassword(saSecure.aesEncrypt(passwordResetDto.getNewPassword()));
        updateById(dbUser);
        return SaResult.ok("密码修改成功，下次登录生效！");
    }

    @Override
    public List<UserVo> doListAll() {
        return lambdaQuery()
                .list()
                .stream()
                .map(this::convertToUserVo)
                .collect(Collectors.toList());
    }

    /**
     * @param user 用户实体
     * @return cn.cq.admin.entity.vo.UserVo
     * @description 将实体类装换为vo类
     * @author jmz
     * @date 2020/7/10 22:09
     */
    private UserVo convertToUserVo(TUser user) {
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        userVo.setId(String.valueOf(user.getId()));
        userVo.setDeptId(String.valueOf(user.getDeptId()));
        userVo.setRoleId(String.valueOf(user.getRoleId()));
        userVo.setMobile(DesensitizedUtil.mobilePhone(user.getMobile()));
        userVo.setEmail(DesensitizedUtil.email(user.getEmail()));
        return userVo;
    }

    /**
     * @param user   用户实体
     * @param dbUser 数据库中的用户实体
     * @return cn.dev33.satoken.util.SaResult
     * @description 验证用户信息
     * @author jmz
     * @date 2020/7/10 22:09
     */
    private SaResult validateUser(TUser user, TUser dbUser) {
        if (dbUser.getJobNo().equals(user.getJobNo())) {
            return SaResult.error("工号已存在！");
        } else if (dbUser.getMobile().equals(user.getMobile())) {
            return SaResult.error("手机号已存在！");
        } else if (dbUser.getEmail().equals(user.getEmail())) {
            return SaResult.error("邮箱已存在！");
        }
        return SaResult.ok();
    }

    /**
     * 通过roleId获取对应的资源信息
     *
     * @param roleId
     * @return
     */
    private List<String> getUserSource(Long roleId) {
        List<TResource> resourceList = new ArrayList<>();
        TRole role = roleService.getById(roleId);
        if (!ObjectUtils.isEmpty(role)) {
            if (BaseConst.SUPER_ADMIN.equals(role.getValue())) {
                resourceList = resourceService.list();
            } else {
                QueryWrapper<TResource> sourceQueryWrapper = new QueryWrapper<>();
                sourceQueryWrapper.inSql("id", "select trr.resource_id from t_role_resource trr, t_role tr " +
                        "where trr.role_id = tr.id " +
                        //获取启用状态角色对应的资源信息
                        "and tr.status = 1 " +
                        "and tr.id = " + roleId);
                resourceList = resourceService.list(sourceQueryWrapper);
            }
        }
        List<String> sources = resourceList.stream()
                .map(resource -> resource.getSourceKey()).collect(Collectors.toList());
        return sources;
    }
}




